Annual Position Review Button - #662
Conversation
…ed logic file for annual position review
… email template page
…eview btn AND annualPositionReview.html handles the confirmation
| supervisors, laborCoordinators = getSupervisors(department) | ||
| recipients = {person["email"] for person in supervisors + laborCoordinators if person["email"]} | ||
| if not recipients: | ||
| continue |
There was a problem hiding this comment.
Should we still create or update the PositionReview record for this department even if there are no email recipients?
The PR description says the system keeps a record of when a review was requested for each department and academic year. Right now, departments with no supervisors/coordinators are skipped before the PositionReview record is created, so those departments will have no record of the request.
| */ | ||
| var academicYear = $('[data-target="#annualPositionModal"]').data('academic-year'); | ||
|
|
||
| $.ajax({ |
There was a problem hiding this comment.
Can we add an error callback here?
Right now, if the server returns 403, 500, or the request fails, the modal will likely stay open and the user will not get a clear message. The success handler handles {"Success": false}, but it does not handle actual AJAX errors.
|
|
||
| try: | ||
| rsp = request.get_json() | ||
| result = sendAnnualPositionReviewRequests(int(rsp['academicYear']), currentUser) |
There was a problem hiding this comment.
Can we validate rsp and academicYear before calling int()?
If the request body is missing, not JSON, or does not include academicYear, this will raise an exception and return {"Success": false} with a 200 response. It would be cleaner to return a 400 with a clear message for bad input.
| from app.logic.getSupervisors import getSupervisors | ||
|
|
||
|
|
||
| def sendMail(mail, message: Message): |
There was a problem hiding this comment.
This sendMail function looks very similar to the existing emailHandler.send logic. Can we reuse the existing email sending helper or extract the shared behavior so we do not have two versions of the same mail override / reply_to / testing behavior?
There was a problem hiding this comment.
i just got rid of annualPositionReview.py and move both the sendAnnualPositionReviewRequests() and sendMail() into emailHandler.py so that i can just use the function as send() to remove the duplicate
| with mainDB.atomic() as transaction: | ||
| Department.update(isActive=False).where(Department.isActive == True).execute() | ||
|
|
||
|
|
There was a problem hiding this comment.
This logic test is helpful. Can we also add a route-level test for /admin/manageDepartments/annualPositionReview?
I think we should test that non-admin users get 403 and that missing or invalid academicYear input returns a clear error. That would cover the endpoint behavior, not just the helper function.
| <button type="button" class="btn btn-primary" onclick="">Submit Request</button> | ||
| <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button> | ||
| <a class="btn btn-info" href="/admin/emailTemplates?audience=Department&formType=Position%20Review&action=Annual%20Request">Edit Email Template</a> | ||
| <button type="button" class="btn btn-primary" onclick="submitAnnualPositionReview()">Submit Request</button> |
There was a problem hiding this comment.
Can we disable this Submit Request button while the AJAX request is running?
Since this sends emails to all active departments, a double-click could send the same email request more than once. The PositionReview table avoids duplicate records, but the emails could still go out multiple times.
| for department in departments: | ||
| supervisors, laborCoordinators = getSupervisors(department) | ||
| recipients = {person["email"] for person in supervisors + laborCoordinators if person["email"]} | ||
| if not recipients: |
There was a problem hiding this comment.
when a department has no supervisors/coordinators with an email, it's skipped with zero logging. No way to tell from logs which departments were skipped or why.
| var category, msg; | ||
| if (response["Success"]) { | ||
| category = "success"; | ||
| msg = "Position review requests sent to " + response["sentCount"] + " of " + response["departmentCount"] + " departments."; | ||
| } else { | ||
| category = "danger"; | ||
| msg = "Something went wrong sending the Annual Position Review requests."; | ||
| } |
There was a problem hiding this comment.
the UI only shows "Success" or "Something went wrong," so an admin can't tell which departments were reached before a failure.
ArtemKurasov
left a comment
There was a problem hiding this comment.
The code is good overall, but I saw several print statements in the code. You should consider deleting them if they serve no purpose other than debugging
| result = sendAnnualPositionReviewRequests(int(rsp['academicYear']), currentUser) | ||
| return jsonify({"Success": True, **result}) | ||
| except Exception as e: | ||
| print(e) |
There was a problem hiding this comment.
Do we need this print statement (line 114)?
Fixes issue #618
The Labor Office should be able to initiate the annual position review process for every department from the Manage Departments page.
This workflow requests departments to review their position descriptions and submit any necessary updates before the next academic year.
Additions
A working "Annual Position Review" button on the Manage Departments page. Clicking it opens a confirmation window explaining what's about to happen.
An "Edit Email Template" option in that confirmation window, so an admin can review or change the wording of the email before sending it.
A "Submit Request" button that actually sends the request. Once sent, every active department's supervisors and Labor Coordinators receive an email asking them to review their positions for the current academic year.
A confirmation message on screen after sending, showing how many departments the request went out to.
The system now keeps a record of when a review was requested for each department and academic year, and who requested it, so re-sending a request updates that record instead of creating duplicates.
Changes
annualPositionReview.html— the previously-stubbed confirmation modal (empty onclick="" on every button) is now fully wired: Submit Request calls the new JS, Edit Email Template links toemailTemplateslinked to this templatemanageDepartments.htmlloadsannualPositionReview.js; the trigger button now carries data-academic-year so the JS knows which academic year is selected.manageDepartments() view now also passes the chosenAY Term object into the template context (previously only chosenAY.termName was passed), needed for the data-academic-year attribute above.
emailTemplates.jsadded prefillFromQueryParams() so the Email Templates editor can be linked with Recipient/Form Type/Action pre-selected (used by the Edit Email Template link above)The confirmation page and its buttons (Cancel, Edit Email Template, Submit Request) previously did nothing when clicked they're now fully functional.
The email template editor page can now be opened directly from the confirmation window with the right template already selected, instead of requiring the admin to fill it manually.
Added the test suite for
annualPositionReview.pyTesting
ALWAYS_SEND_MAIL was set to False in local secret_config.yaml (untracked, not part of this PR) so local testing doesn't attempt a real SMTP send.
To submit an annual position review, on the sidebar menu, click Admin
Then click the " Manage Department " that will take you to the page
On the page click "Annual Position Review" and then " Submit Request"
A message will show that the request has been sent to x departments out of y.
Two ways to edit email template through Manage Department and Manage Email Template: